package cn.js.sangu.unitStore.service.process;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.js.sangu.unitStore.entity.BomDe;
import cn.js.sangu.unitStore.entity.CodeLib;
import cn.js.sangu.unitStore.service.CodeLibService;
import lombok.extern.slf4j.Slf4j;

/**
 * 属性自检工具：
 * 
 * 
 */
@Slf4j
@Service
public class PartAttributesCheck {

    @Autowired
    CodeLibService codeLibService;

    // 获取codeLibService实例的方法
    public CodeLibService getCodeLibService() {
        return this.codeLibService;
    }

    /**
     * 在编码之前，根据属性检查在码库中是否存在相同零件，存在则直接返回。
     */
    public String beforeEncoding(String tuhao, String name, String cailiao, String guige, String leibie) {
        // 先根据tuhao、name、cailiao、guige、leibie五个属性从codeLib匹配
        try {
            List<CodeLib> codeLibList = codeLibService.lambdaQuery()
                    .eq(CodeLib::getTuhao, tuhao)
                    .eq(CodeLib::getName, name)
                    .eq(CodeLib::getCailiao, cailiao)
                    .eq(CodeLib::getGuige, guige)
                    .eq(CodeLib::getLeibie, leibie)
                    .list();

            if (codeLibList != null && !codeLibList.isEmpty()) {
                // 如果匹配到，直接返回syscode
                String syscode = codeLibList.get(0).getSyscode();
                // log.info("从编码历史库匹配到编码：图号={}, 名称={}, 材料={}, 规格={}, 类别={}, 编码={}", tuhao, name,
                // cailiao, guige, leibie,
                // syscode);
                return syscode;
            } else {
                return null;
            }
        } catch (Exception e) {
            log.error("从编码历史库查询时发生异常：图号={}, 名称={}, 材料={}, 规格={}, 类别={}, 异常信息={}", tuhao, name, cailiao, guige, leibie,
                    e.getMessage());
            // 发生异常时继续执行后续编码生成逻辑
            return null;
        }
    }

    /**
     * 编码生成后的处理，包括格式标准化和重复检查
     * 
     * @param res                生成的编码
     * @param questionMarkHandle 问号处理方式设置 (0:保留问号, 1:替换问号为随机数, 2:替换问号为零)
     * @return 处理后的标准化编码
     */
    public String afterEncoding(String res, String questionMarkHandle) {
        // 特殊编码：14位0，表示有特殊意义，不参与检验
        final String SPECIAL_CODE = "00000000000000";

        // 检查是否为特殊编码
        if (SPECIAL_CODE.equals(res)) {
            return res;
        }

        // 如果编码为空，返回特殊编码
        if (res == null) {
            return SPECIAL_CODE;
        }

        // 根据设置决定是否保留问号
        boolean keepQuestionMarks = "0".equals(questionMarkHandle); // 0表示保留问号

        // 构建清理后的编码，根据设置决定是否保留问号
        StringBuilder cleanCodeBuilder = new StringBuilder();
        for (char c : res.toCharArray()) {
            if (Character.isDigit(c) || (keepQuestionMarks && c == '?')) {
                cleanCodeBuilder.append(c);
            }
        }
        String cleanCode = cleanCodeBuilder.toString();

        String fixedCode;
        Random random = new Random();

        // 根据编码长度进行处理
        if (cleanCode.length() < 14) {
            // 编码不足14位，在末尾补充随机数
            fixedCode = cleanCode;
            while (fixedCode.length() < 14) {
                fixedCode += random.nextInt(10);
            }
        } else if (cleanCode.length() > 14) {
            // 编码大于14位，减掉末尾多余的数字
            fixedCode = cleanCode.substring(0, 14);
        } else {
            // 编码正好14位
            fixedCode = cleanCode;
        }

        // 若编码中第8位-第14位中若有连续的5个0，则替换为5位随机数
        if (fixedCode.length() >= 14) {
            // 提取第8-14位（索引7-13）
            String targetSegment = fixedCode.substring(7, 14);
            // 使用正则表达式查找连续的5个0
            Pattern fiveZeroPattern = Pattern.compile("0{5}");
            Matcher matcher = fiveZeroPattern.matcher(targetSegment);

            if (matcher.find()) {
                // 生成5位随机数，避免生成全0
                String randomDigits;
                do {
                    randomDigits = String.format("%05d", random.nextInt(100000));
                } while ("00000".equals(randomDigits));

                // 替换找到的第一个连续5个0
                String modifiedSegment = matcher.replaceFirst(randomDigits);
                // 重新组合整个编码
                fixedCode = fixedCode.substring(0, 7) + modifiedSegment + fixedCode.substring(14);
            }
        }

        // 检查编码是否与数据库中的编码重复
        try {
            boolean isDuplicate = true;
            while (isDuplicate) {
                // 从数据库查询是否存在相同编码
                List<CodeLib> existingCodes = codeLibService.lambdaQuery()
                        .eq(CodeLib::getSyscode, fixedCode)
                        .list();

                if (existingCodes != null && !existingCodes.isEmpty()) {
                    // 编码重复，修改末尾两位数字为随机数
                    String prefix = fixedCode.substring(0, 12);
                    String randomSuffix = String.format("%02d", random.nextInt(100));
                    fixedCode = prefix + randomSuffix;
                } else {
                    // 编码不重复，结束循环
                    isDuplicate = false;
                }
            }
        } catch (Exception e) {
            log.error("检查编码重复时发生异常：{}", e.getMessage());
            // 发生异常时不中断流程，返回当前已修复格式的编码
        }

        return fixedCode;
    }

    /**
     * 在编码之后，根据生成的编码检验格式是否正确，若有不足则自动优化后返回。
     * 验证并修复编码格式和重复问题
     * 规则：
     * 1. 若编码14位都是0表示有特殊意义不参与检验
     * 2. 若编码不足14位，则在末尾补充随机数以达到14位
     * 3. 若编码大于14位，则减掉末尾多余的数字以达到14位
     * 4. 若此编码与其他编码有重复则更改末尾两位数字为随机数，直到不重复为止
     * 
     * @param bomDeList 零件列表
     */
    public void validateAndFixCodes(List<BomDe> bomDeList) {
        log.info("开始验证和修复编码格式，总记录数：{}", bomDeList.size());

        // 用于检测重复编码
        Set<String> codeSet = new HashSet<>();
        // 用于存储相同零件(tuhao, name, cailiao都相同)的编码映射
        Map<String, String> partCodeMap = new HashMap<>();
        int formatFixCount = 0;
        int duplicateFixCount = 0;
        int dbConflictFixCount = 0;
        // 特殊编码：14位0，表示有特殊意义
        final String SPECIAL_CODE = "00000000000000";

        // 从数据库加载已存在的编码，避免新生成的编码与历史编码重复
        Set<String> existingCodesFromDb = new HashSet<>();
        try {
            log.info("从编码库加载已存在的编码，避免编码冲突");
            List<CodeLib> allLibs = codeLibService.list();
            for (CodeLib lib : allLibs) {
                if (lib.getSyscode() != null && !SPECIAL_CODE.equals(lib.getSyscode())) {
                    existingCodesFromDb.add(lib.getSyscode());
                }
            }
            log.info("成功加载 {} 个已存在的编码", existingCodesFromDb.size());
        } catch (Exception e) {
            log.error("从编码库加载已存在编码时发生异常：{}", e.getMessage());
            // 不中断流程，继续执行，只是可能存在风险
        }

        // 对列表进行遍历，检查编码格式
        for (BomDe bomDe : bomDeList) {
            String syscode = bomDe.getSyscode();
            String originalCode = syscode;

            // 检查是否为特殊编码（14位0）
            boolean isSpecialCode = SPECIAL_CODE.equals(syscode);

            // 特殊编码不参与检验，跳过后续处理
            if (isSpecialCode) {
                continue;
            }

            // 如果编码为空，设置为空字符串以便后续处理
            if (syscode == null) {
                syscode = "";
            }

            // 确保编码只包含数字字符
            StringBuilder cleanCodeBuilder = new StringBuilder();
            for (char c : syscode.toCharArray()) {
                if (Character.isDigit(c)) {
                    cleanCodeBuilder.append(c);
                }
            }
            String cleanCode = cleanCodeBuilder.toString();

            String fixedCode;

            // 根据编码长度进行处理
            if (cleanCode.length() < 14) {
                // 编码不足14位，在末尾补充随机数
                fixedCode = cleanCode;
                Random random = new Random();
                while (fixedCode.length() < 14) {
                    fixedCode += random.nextInt(10);
                }
                formatFixCount++;
            } else if (cleanCode.length() > 14) {
                // 编码大于14位，减掉末尾多余的数字
                fixedCode = cleanCode.substring(0, 14);
                formatFixCount++;
            } else {
                // 编码正好14位
                fixedCode = cleanCode;
            }

            // 创建零件唯一标识：由tuhao、name、cailiao、guige、leibie组成
            String tuhao = bomDe.getTuhao() != null ? bomDe.getTuhao().trim() : "NULL_TUHAO";
            String name = bomDe.getName() != null ? bomDe.getName().trim() : "NULL_NAME";
            String cailiao = bomDe.getCailiao() != null ? bomDe.getCailiao().trim() : "NULL_CAILIAO";
            String guige = bomDe.getGuige() != null ? bomDe.getGuige() : "NULL_GUIGE";
            String leibie = bomDe.getLeibie() != null ? bomDe.getLeibie() : "NULL_LEIBIE";
            String partKey = tuhao + "_" + name + "_" + cailiao + "_" + guige + "_" + leibie;

            // 处理重复编码：
            // 1. 如果是同一个零件(tuhao、name、cailiao、guige、leibie都相同)，即使编码相同也不视为重复
            // 2. 如果是不同零件但编码重复，则更改末尾三位数字为随机数
            if (partCodeMap.containsKey(partKey)) {
                // 同一个零件，直接使用已存在的编码
                String existingCode = partCodeMap.get(partKey);
                if (!fixedCode.equals(existingCode)) {
                    fixedCode = existingCode;
                    // 记录编码变更，但不计入重复修复计数
                    // if (!fixedCode.equals(originalCode)) {
                    // log.warn("编码异常已修复：原始编码={}, 修复后编码={}, 图号={}, 名称={}",
                    // originalCode, fixedCode, bomDe.getTuhao(), bomDe.getName());
                    // }
                }
            } else {
                Random random = new Random();
                // 不同零件，检查编码是否重复，同时考虑当前批次和数据库中已有的编码
                boolean needFix = codeSet.contains(fixedCode) || existingCodesFromDb.contains(fixedCode);

                while (needFix) {
                    // 保留前11位，后三位用随机数替换
                    String prefix = fixedCode.substring(0, 11);
                    String randomSuffix = String.format("%03d", random.nextInt(1000));
                    fixedCode = prefix + randomSuffix;

                    // 检查新生成的编码是否仍然重复
                    needFix = codeSet.contains(fixedCode) || existingCodesFromDb.contains(fixedCode);

                    // 判断是当前批次重复还是数据库重复
                    if (codeSet.contains(fixedCode)) {
                        duplicateFixCount++;
                    } else if (existingCodesFromDb.contains(fixedCode)) {
                        dbConflictFixCount++;
                    }
                }

                // 保存零件与编码的映射关系
                partCodeMap.put(partKey, fixedCode);
                // 添加到编码集合中
                codeSet.add(fixedCode);
            }

            // 更新编码
            bomDe.setSyscode(fixedCode);

            // 如果编码有变动，记录日志
            // if (!fixedCode.equals(originalCode)) {
            // log.warn("编码异常已修复：原始编码={}, 修复后编码={}, 图号={}, 名称={}",
            // originalCode, fixedCode, bomDe.getTuhao(), bomDe.getName());
            // }
        }
        log.info("编码验证和修复完成：修复格式异常 {} 条，修复批次内重复异常 {} 条，修复数据库重复冲突 {} 条",
                formatFixCount, duplicateFixCount, dbConflictFixCount);
    }

}
